#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>

#include <string>
#include <vector>
using namespace std;

namespace AchievementSystem
{

	class AchievementData
	{
		int iData;
		std::string message;

	public:
		// Constructor
		AchievementData(void) : iData(0) {}

		void SetData(int data) { iData = data; }
		void SetEventMessage(std::string msg);
		void SetEventMessage(const char* msg);

		int GetIntData(void) const { return iData; }
		std::string GetEventMessage(void) const { return message; }
	};

	struct Achievement
	{
		enum IncrementType { ADD, SUB, SET, NONE };
		enum ComparisonType { LessThan, GreaterThan, EqualTo, LessThanEqualTo, GreaterThanEqualTo, NotEqualTo };

	private:

		string name;
		string message;
		string description;
		IncrementType increment;
		ComparisonType comparison;
		int value;
		int target;

	public:

		// Constructor
		Achievement(void);

		// Destructor
		~Achievement(void);

		//////////////////////////////////////////////////
		// Accessors:
		string GetName(void) const;
		string GetAchievementMessage(void) const;
		string GetDescription(void) const;
		ComparisonType GetComparisonType(void) const;
		IncrementType GetIncrementType(void) const;
		int GetValue(void) const;
		int GetTarget(void) const;

		//////////////////////////////////////////////////
		// Mutators:
		void SetName(string name);
		void SetMessage(string message);
		void SetDescription(string description);
		void SetComparisonType(ComparisonType comparision);
		void SetIncrementType(IncrementType increment);
		void SetValue(int value);
		void SetTarget(int target);

		//////////////////////////////////////////////////
		// Helper Methods:
		static ComparisonType GetComparisonTypeFromString(string strType);
		static IncrementType GetIncrementTypeFromString(string strType);

	};

	class AchievementManager
	{
	private:
		// Singleton: Hide access.
		AchievementManager(void);
		AchievementManager(const AchievementManager&);
		AchievementManager& operator=(const AchievementManager&);
		~AchievementManager(void);

		//////////////////////////////////////////////////
		// Members:
		vector<Achievement> currentAchievements;
		vector<Achievement> completedAchievements;

		int fontID;

		RECT displayRect;

		int displayWidth;	// The width of the RECT used to display the achievement.
		int displayHeight;	// The height of the RECT used to display the achievement.
		int displayPadding;	// The number of pixels added to each side of the text to pad the display RECT.

		float displaySpeed;

		bool displayAchievement;

		float displayTime;
		float displayTimer;

		string displayName;

	public:

		//////////////////////////////////////////////////
		// Accessors:
		const Achievement* GetAchievement(string name) const;
		const vector<Achievement>& CompleteAchievements(void) const;
		const vector<Achievement>& IncompleteAchievements(void) const;

		//////////////////////////////////////////////////
		// Mutators:
		void AddAchievement(const Achievement& achievement);
		bool RemoveAchievement(string name);
		void ClearAchievements(void);

		//////////////////////////////////////////////////
		// Methods:
		static AchievementManager& GetInstance(void);
		// Author: Joshua Bramer
		// Description:
		//		- Sends achievement data to the AchievementManager to be processed.
		// Parameters:
		//		data		-	A structure containing data about the acheivement.
		// Notes:
		//		- The AchievementManager will look for an achievement waiting for the message.
		//		   If one is found, the achievement will be updated. If none is found, the manager
		//		   will simply ignore the event call.
		void SendEvent(AchievementData data);
		// Author: Joshua Bramer
		// Description:
		//		- Sends achievement data to the AchievementManager to be processed.
		// Parameters:
		//		message		-	The name of the achievement.
		//		data				-	An integer value used to update the achievement.
		//								Example: If data is 1, then the Achievement Manager might add 1 to a counter.
		// Notes:
		//		- The AchievementManager will look for an achievement waiting for the message.
		//		   If one is found, the achievement will be updated. If none is found, the manager
		//		   will simply ignore the event call.
		void SendEvent(string message, int data);
		void Update(float deltaTime);
		void Render(void) const;
		bool LoadAchievements(const char* fileName);
		void SetAchievementCompleted(string name);
		void SetAchievementProgress(string name, int value);

	private:

		//////////////////////////////////////////////////
		// Helper Methods:
		void DeclareAchievementCompleted(Achievement achievement);
		bool CheckAchievementForCompletion(Achievement achievement);
	};

}

